#!/usr/bin/python
# -*- coding: UTF-8 -*-

from __future__ import print_function
import frida
import sys  

reload(sys)  
sys.setdefaultencoding('utf8')

def on_message(message, data):
    print("[%s] => %s" % (message, data))

def main(device, target_process):
    session = device.attach(target_process)

    script = session.create_script("""

function set_read_write_break(addr, size, pattern)
{

        //设置异常
    Process.setExceptionHandler(function(details){
                //打印信息，e.g. 打印堆栈，打印发生异常的地址，打印引发异常的地址
                /*
                        type: string specifying one of:
                                abort
                                access-violation
                                guard-page
                                illegal-instruction
                                stack-overflow
                                arithmetic
                                breakpoint
                                single-step
                                system
                        address: address where the exception occurred, as a NativePointer
                        memory: if present, is an object containing:
                                operation: the kind of operation that triggered the exception, as a string specifying either read,  write, or execute
                                address: address that was accessed when the exception occurred, as a NativePointer
                        context: object with the keys pc and sp, which are NativePointer objects specifying EIP/RIP/PC and ESP/RSP/SP, respectively, for ia32/x64/arm. Other processor-specific keys are also available, e.g. eax, rax, r0, x0, etc. You may also update register values by assigning to these keys.
                        nativeContext: address of the OS and architecture-specific CPU context struct, as a NativePointer. This is only exposed as a last resort for edge-cases where context isn’t providing enough details. We would however discourage using this and rather submit a pull-request to add the missing bits needed for your use-case.                
                                        
                */

                //处理异常
                Memory.protect(addr, size, 'rwx');


                send(details.type);
                send(details.address);
                send(details.memory);

                var backtrace = Thread.backtrace(details.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\\n\\t');
                
                //console.log(backtrace);
                send(backtrace);

                return true;
        });
        //制造异常 <--> 设置读写断点
        Memory.protect(addr, size, pattern);
}


Interceptor.attach(Module.findExportByName("libc-2.27.so" , "open"), {
    onEnter: function(args) {
        console.log(typeof args[0]);
        console.log(args[0]);
        send("open called! args[0]:" + Memory.readUtf8String(args[0]));
        set_read_write_break(args[0], 4, '---');
    },
    onLeave:function(retval){
    
    }
});
""")
    script.on('message', on_message)
    script.load()
    print("hook done\n")
    sys.stdin.read()
    session.detach()

if __name__ == '__main__':
    if len(sys.argv) != 2:
        print("Usage: %s <process name or PID>" % __file__)
        sys.exit(1)

    device = frida.get_device_manager().add_remote_device('192.168.245.132:1124')

    try:
        target_process = int(sys.argv[1])
    except ValueError:
        target_process = sys.argv[1]
    main(device, target_process)